package top.codef.crypt.aes;

import java.security.AlgorithmParameters;
import java.security.InvalidKeyException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Security;
import java.security.spec.AlgorithmParameterSpec;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import top.codef.crypt.CryptException;

public class AESAdvancedKeyPair {

	private static final String AES = "AES";

	private final byte[] encryptKey;

	private final AlgorithmParameterSpec algorithmParameterSpec;

	private final int mode;

	private final String cryptAlgorithm;

	private final byte[] additionalAuthData;

	static {
		Security.addProvider(new BouncyCastleProvider());
	}

	protected AESAdvancedKeyPair(AesAlgorithm aesAlgorithm, byte[] encryptKey, byte[] ivByte, byte[] additionalAuthData,
			int mode) {
		this.encryptKey = encryptKey;
		algorithmParameterSpec = ivByte == null ? null : aesAlgorithm.generrateParameterSpec(128, ivByte);
		this.mode = mode;
		cryptAlgorithm = aesAlgorithm.getAlgorithm();
		this.additionalAuthData = additionalAuthData;
	}

	public static AESAdvancedKeyPair instance(AesAlgorithm aesAlgorithm, byte[] encryptKey, byte[] ivByte, int mode) {
		try {
			return new AESAdvancedKeyPair(aesAlgorithm, encryptKey, ivByte, null, mode);
		} catch (Exception e) {
			throw new CryptException("生成AES秘钥错误", e);
		}
	}

	public static AESAdvancedKeyPair instance(AesAlgorithm aesAlgorithm, byte[] encryptKey, byte[] ivByte,
			byte[] additionalAuthData, int mode) {
		try {
			return new AESAdvancedKeyPair(aesAlgorithm, encryptKey, ivByte, additionalAuthData, mode);
		} catch (Exception e) {
			throw new CryptException("生成AES秘钥错误", e);
		}
	}

	public static AESAdvancedKeyPair instance(AesAlgorithm aesAlgorithm, byte[] encryptKey, int mode) {
		try {
			return new AESAdvancedKeyPair(aesAlgorithm, encryptKey, null, null, mode);
		} catch (Exception e) {
			throw new CryptException("生成AES秘钥错误", e);
		}
	}

	public static byte[] genericKey() throws Exception {
		KeyGenerator generator = KeyGenerator.getInstance(AES);
		generator.init(128, SecureRandom.getInstanceStrong());
		SecretKey secretKey = generator.generateKey();
		return secretKey.getEncoded();
	}

	public static byte[] genericKey(int size) throws Exception {
		KeyGenerator generator = KeyGenerator.getInstance(AES);
		generator.init(size, SecureRandom.getInstanceStrong());
		SecretKey secretKey = generator.generateKey();
		return secretKey.getEncoded();
	}

	/**
	 * 
	 * @param originalContent
	 * @param encryptKey
	 * @param ivByte
	 * @return
	 */
	public byte[] encrypt(byte[] originalContent) {
		try {
			Cipher cipher = Cipher.getInstance(cryptAlgorithm);
			SecretKeySpec skeySpec = new SecretKeySpec(encryptKey, AES);
			cipher.init(mode, skeySpec, algorithmParameterSpec);
			if (additionalAuthData != null) {
				cipher.updateAAD(additionalAuthData);
			}
			byte[] encrypted = cipher.doFinal(originalContent);
			return encrypted;
		} catch (Exception e) {
			throw new CryptException("加密错误错误", e);
		}
	}

	/**
	 * AES解密 填充模式AES/CBC/PKCS7Padding 解密模式128
	 * 
	 * @param content 目标密文
	 * @return
	 * @throws Exception
	 * @throws InvalidKeyException
	 * @throws NoSuchProviderException
	 */
	public byte[] decrypt(byte[] content) {
		try {
			Cipher cipher = Cipher.getInstance(cryptAlgorithm);
			SecretKeySpec skeySpec = new SecretKeySpec(encryptKey, AES);
			cipher.init(mode, skeySpec, algorithmParameterSpec);
			if (additionalAuthData != null) {
				cipher.updateAAD(additionalAuthData);
			}
			byte[] result = cipher.doFinal(content);
			return result;
		} catch (Exception e) {
			throw new CryptException("解密错误", e);
		}
	}

	// 生成iv
	public static AlgorithmParameters generateIV(byte[] iv) throws Exception {
		AlgorithmParameters params = AlgorithmParameters.getInstance(AES);
		params.init(new IvParameterSpec(iv));
		return params;
	}

}
